from logging import exception
import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# ---------------------- 全局配置（根据需求修改） ----------------------
# 1. 设备信息（adb devices获取）
DEVICE_NAME = "SM-G988N"  # 模拟器/真实设备序列号
# 2. Appium Server地址
APPIUM_SERVER_URL = "http://localhost:4723/wd/hub"
# 3. 朋友圈配置
MOMENTS_CONTENTS = [  # 预设内容（循环使用）
    "第一条带图朋友圈：Appium自动化测试",
    "第二条带图朋友圈：今天分享一组照片",
    "第三条带图朋友圈：自动化选图真方便！",
    "第四条带图朋友圈：测试循环发送功能",
    "第五条带图朋友圈：30分钟间隔完成"
]
CYCLE_TIMES = 3  # 循环发送次数（N次）
INTERVAL_SECONDS = 1800  # 每次循环间隔（30分钟=1800秒）
MAX_IMAGES = 9  # 朋友圈最多选9张图


# ---------------------- Appium Desired Capabilities ----------------------
desired_caps = {
    "platformName": "Android",
    "deviceName": DEVICE_NAME,
    "appPackage": "com.tencent.mm",  # 微信包名
    "appActivity": "com.tencent.mm.ui.LauncherUI",  # 微信启动页
    "noReset": True,  # 保留登录状态（首次需手动登录）
    "automationName": "UiAutomator2",  # 必须用UiAutomator2（支持复杂操作）
    "unicodeKeyboard": True,  # 解决中文输入乱码
    "resetKeyboard": True,  # 脚本结束后恢复键盘
    "newCommandTimeout": 3600  # 延长命令超时时间（避免30分钟间隔被判定超时）
}


# ---------------------- 工具函数 ----------------------
def handle_popups(driver, wait):
    """处理微信启动时的弹窗（如更新、权限、引导页）"""
    popups = [
        ("//*[@text='取消']", "更新提示"),
        ("//*[@text='我知道了']", "功能引导"),
        ("//*[@text='以后再说']", "权限请求")
    ]
    for xpath, desc in popups:
        try:
            btn = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
            btn.click()
            print(f"✅ 处理弹窗：{desc}")
            time.sleep(2)
        except Exception:
            pass


def post_moment_with_images(driver, wait, content, cycle_num):
    """发送一条带图朋友圈（选前9张或全部）"""
    try:
        # 1. 点击「发现」页
        discover_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@text='发现']")))
        discover_btn.click()
        print(f"→ 第{cycle_num}次：进入发现页")
        time.sleep(2)

        # 2. 打开「朋友圈」
        moments_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@text='朋友圈']")))
        moments_btn.click()
        print(f"→ 第{cycle_num}次：进入朋友圈")
        time.sleep(2)

        # 3. 点击右上角相机图标（触发发朋友圈选项）
        camera_icon = wait.until(EC.presence_of_element_located(
            (By.XPATH, "//android.widget.ImageView[@content-desc='拍照分享']")
            # By.ID, "com.tencent.mm:id/eo"   # 拍照分享
        ))
        camera_icon.click()
        print(f"→ 第{cycle_num}次：点击相机图标")
        time.sleep(2)

        # 4. 选择「从相册选择」
        album_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@text='从相册选择']")))
        album_btn.click()
        print(f"→ 第{cycle_num}次：进入相册")
        time.sleep(2)  # 等待相册加载

        # 5. 处理相册分层（部分手机需先选「所有照片」文件夹）
        try:
            all_photos_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@text='所有照片']")))
            all_photos_btn.click()
            print(f"→ 第{cycle_num}次：进入所有照片文件夹")
            time.sleep(2)
        except Exception:
            print(f"→ 第{cycle_num}次：未检测到相册分层，直接选图")

        # 6. 选择前N张图（最多9张）
        # ① 定位「所有图片项的父容器」（必须是复选框的直接外层！用Appium Inspector确认）
            # 说明：每个父容器包含「图片+右上角复选框」，这里用RelativeLayout（根据你的界面调整）
            image_items_xpath = "//androidx.recyclerview.widget.RecyclerView//android.widget.RelativeLayout"
            # 显式等待：确保至少有1个图片项加载完成
            image_items = wait.until(
                EC.presence_of_all_elements_located((By.XPATH, image_items_xpath))
            )
            total_available = len(image_items)
            print(f"→ 第{cycle_num}次：相册共加载{total_available}张图")

            selected_count = 0
            # 最多选9张，若图片不足则选全部
            max_to_select = min(MAX_IMAGES, total_available)

            for idx in range(max_to_select):
                current_item = image_items[idx]  # 当前要选的图片项
                try:
                    # ② 定位当前图片项内的「复选框」（用resource-id，100%稳定）
                    # 重点：必须在「当前图片项（current_item）」内查找，避免全局定位！
                    checkbox = current_item.find_element(
                        By.ID, "com.tencent.mm:id/gpy"  # 你的复选框resource-id
                    )

                    # ③ 确认复选框可点击后再点击（避免元素未初始化）
                    if checkbox.is_enabled() and checkbox.is_displayed():
                        checkbox.click()
                        selected_count += 1
                        print(f"→ 第{cycle_num}次：成功选中第{selected_count}张图")
                        time.sleep(1)  # 防止点击过快导致漏选
                    else:
                        print(f"⚠️ 第{cycle_num}次：第{idx+1}张图的复选框不可交互")
                        break

                except Exception as e:
                    print(f"⚠️ 第{cycle_num}次：选择第{idx+1}张图失败 → {str(e)}")
                    break  # 遇到错误直接终止选图，避免后续混乱

            print(f"→ 第{cycle_num}次：最终选中{selected_count}张图")

        except Exception as e:
            print(f"❌ 第{cycle_num}次：选图逻辑整体失败 → {str(e)}")
            raise e  # 抛出异常，让外层处理
        

        # 7. 确认选图（点击「完成」）
        try:
            # 显式等待：确保“完成”按钮可点击（用resource-id定位）
            done_btn = wait.until(
                EC.element_to_be_clickable((By.ID, "com.tencent.mm:id/en"))  # 替换为你的resource-id
            )
            done_btn.click()
            print(f"→ 第{cycle_num}次：确认选图（点击完成按钮）")
            time.sleep(2)  # 等待进入朋友圈编辑页
        except Exception as e:
            print(f"❌ 第{cycle_num}次：点击完成按钮失败 → {str(e)}")
            raise e  # 抛出异常，终止当前循环

        # 8. 输入朋友圈文字内容（用正确的resource-id定位）
        try:
            # 显式等待：确保输入框「可见且可点击」（更可靠）
            input_box = wait.until(
                EC.element_to_be_clickable((By.ID, "com.tencent.mm:id/jsy"))  # 替换为你的输入框ID
            )
            # 激活输入框（部分场景需先点击才能输入）
            input_box.click()
            input_box.clear()  # 清空残留内容（若有）
            input_box.send_keys(content)  # 输入预设内容
            print(f"→ 第{cycle_num}次：输入内容 → {content}")
            time.sleep(2)  # 等待输入完成（避免内容未完全填入）
        except Exception as e:
            print(f"❌ 第{cycle_num}次：输入内容失败 → {str(e)}")
            raise e

        # 9. 点击「发表」
        post_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@text='发表']")))
        post_btn.click()
        print(f"→ 第{cycle_num}次：点击发表")
        time.sleep(3)  # 等待发表完成（避免未发送成功）

        # 10. 返回微信首页（避免后续操作混乱）
        try:
            home_btn = wait.until(EC.element_to_be_clickable((By.ID, "com.tencent.mm:id/g1")))
            home_btn.click()
            print(f"→ 第{cycle_num}次：返回首页")
            time.sleep(2)
        except exception as e:
            print(f"❌ 第{cycle_num}次：返回首页失败 → {str(e)}")
            raise e

        print(f"✅ 第{cycle_num}次发送成功！内容：{content}，图片：{selected_count}张\n")

    except Exception as e:
        error_msg = f"❌ 第{cycle_num}次发送失败 → {str(e)}"
        print(error_msg)

# ---------------------- 核心任务函数（封装所有逻辑） ----------------------
def run_moments_automation():
    driver = None
    try:
        # 1. 连接Appium Server，启动微信
        driver = webdriver.Remote(APPIUM_SERVER_URL, desired_caps)
        wait = WebDriverWait(driver, 5)  # 延长等待时间（应对微信加载慢）
        print("✅ Appium连接成功，正在启动微信...")

        # 2. 等待微信初始化完成（处理启动慢的问题）
        time.sleep(5)  # 首次启动需更长时间
        handle_popups(driver, wait)
        print("✅ 微信初始化完成，开始执行任务\n")

        # 3. 循环发送朋友圈
        for cycle in range(1, CYCLE_TIMES + 1):
            # 从预设内容中循环取文案（避免重复）
            content = MOMENTS_CONTENTS[cycle % len(MOMENTS_CONTENTS)]
            # 执行发送
            post_moment_with_images(driver, wait, content, cycle)
            # 非最后一次循环，等待30分钟
            if cycle < CYCLE_TIMES:
                print(f"⏳ 等待{INTERVAL_SECONDS//60}分钟后进行第{cycle+1}次发送...\n")
                time.sleep(INTERVAL_SECONDS)

        print("🎉 所有循环任务已完成！")

    except Exception as e:
        print(f"\n❌ 任务整体失败 → {str(e)}")

    finally:
        # 关闭驱动，释放资源
        if driver:
            driver.quit()
            print("🔚 微信驱动已关闭")
        print("🔚 自动化脚本结束")


# ---------------------- 主程序（仅调用核心函数） ----------------------
if __name__ == "__main__":
    run_moments_automation()